package cn.renxuan.service.domesticweather;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.CompletableFuture;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import cn.renxuan.CommonUtil;
import cn.renxuan.constant.SystemVariables;
import cn.renxuan.entity.FS_DomesticWeather;
import cn.renxuan.entity.TB_AdministrativeDivision;
import cn.renxuan.querys.AdministrativeDivisionQuery;
import cn.renxuan.redis.LettuceRedisHelper;
import cn.renxuan.repository.administrativedivision.IAdministrativeDivisionRepository;
import cn.renxuan.repository.domesticweather.IDomesticWeatherRepository;
import cn.renxuan.service.weather.IWeatherService;
import cn.renxuan.service.weather.WeatherConfig;
import cn.renxuan.service.weather.WeatherHelper;

@Service
public class DomesticWeatherService implements IDomesticWeatherService {

    private final IDomesticWeatherRepository Rep;

    private final IAdministrativeDivisionRepository AdministrativeDivisionRep;

    private IWeatherService WeatherSV;

    @Autowired
    public DomesticWeatherService(IDomesticWeatherRepository rep,
            IAdministrativeDivisionRepository administrativeDivisionRep, IWeatherService weatherSV) {
        this.Rep = rep;
        this.WeatherSV = weatherSV;
        this.AdministrativeDivisionRep = administrativeDivisionRep;
    }

    public boolean addLundearWeather(String areaCode) throws Exception {
        int affectedRow = 0;
        try {
            Map<String, String> areaList = getAreaList(areaCode);
            Map<String, String> querys = new HashMap<String, String>();
            querys.put("areaCode", areaCode);
            querys.put("needalarm", "1");
            querys.put("need1hour", "1");
            querys.put("need3hour", "1");
            querys.put("needIndex", "1");
            querys.put("needObserve", "1");
            WeatherConfig weatherConfig = WeatherHelper.getWeatherConfigByPropName("realtimeweather-configKey");
            IWeatherService tempWeatherSV = null;
            if (weatherConfig != null && weatherConfig.getDriverName() != null
                    && !weatherConfig.getDriverName().isBlank()) {
                tempWeatherSV = Class.forName(weatherConfig.getDriverName()).asSubclass(IWeatherService.class)
                        .getDeclaredConstructor().newInstance();
            } else {
                throw new Exception("Baidu weather configuration not found");
            }

            FS_DomesticWeather domesticWeather = tempWeatherSV.getDomesticWeather(querys, null);
            if (domesticWeather != null) {

                if (areaCode.length() >= 6) {
                    String proviceCode = areaCode.substring(0, 2);
                    domesticWeather.setProvincecode(proviceCode);
                    domesticWeather.setProvince(areaList.get(proviceCode));
                    String cityCode = areaCode.substring(0, 4);
                    domesticWeather.setCitycode(cityCode);
                    domesticWeather.setCity(areaList.get(cityCode));
                    String countyCode = areaCode.substring(0, 6);
                    domesticWeather.setCountycode(countyCode);
                    domesticWeather.setCounty(areaList.get(countyCode));
                } else if (areaCode.length() >= 4) {
                    String proviceCode = areaCode.substring(0, 2);
                    domesticWeather.setProvincecode(proviceCode);
                    domesticWeather.setProvince(areaList.get(proviceCode));
                    String cityCode = areaCode.substring(0, 4);
                    domesticWeather.setCitycode(cityCode);
                    domesticWeather.setCity(areaList.get(cityCode));
                } else if (areaCode.length() >= 2) {
                    String proviceCode = areaCode.substring(0, 2);
                    domesticWeather.setProvincecode(proviceCode);
                    domesticWeather.setProvince(areaList.get(proviceCode));
                } else {
                    throw new Exception("Invalid area code length: " + areaCode.length());
                }

                List<String> ignoreColumns = new ArrayList<String>();
                ignoreColumns.add("id");
                CompletableFuture<Integer> addFuture = Rep.addAsync(
                        (Class<FS_DomesticWeather>) domesticWeather.getClass(),
                        domesticWeather,
                        ignoreColumns);
                affectedRow = addFuture.join();
            }
        } catch (Exception ex) {
            CommonUtil.printThreadLog("出现异常：" + ex.getMessage());
        }
        return affectedRow > 0;
    }

    /*
     * 添加百度天气数据
     */
    public boolean addBaiduWeather(String areaCode) throws Exception {
        int affectedRow = 0;
        try {
            Map<String, String> areaList = getAreaList(areaCode);
            Map<String, String> querys = new HashMap<String, String>();
            querys.put("district_id", areaCode);
            querys.put("data_type", "all");
            WeatherConfig weatherConfig = WeatherHelper.getWeatherConfigByPropName("baidu-map-configKey");
            IWeatherService tempWeatherSV = null;
            if (weatherConfig != null && weatherConfig.getDriverName() != null
                    && !weatherConfig.getDriverName().isBlank()) {
                tempWeatherSV = Class.forName(weatherConfig.getDriverName()).asSubclass(IWeatherService.class)
                        .getDeclaredConstructor().newInstance();
                if (!weatherConfig.getApiCode().isBlank()) {
                    querys.put("ak", weatherConfig.getApiCode().trim());
                }
            } else {
                throw new Exception("Baidu weather configuration not found");
            }
            FS_DomesticWeather domesticWeather = tempWeatherSV.getDomesticWeather(querys, null);
            if (domesticWeather != null) {

                areaCode = domesticWeather.getCountycode();
                if (!areaList.containsKey(areaCode)) {
                    throw new Exception("Area code not found in area list: " + domesticWeather.getCountycode());
                }

                if (areaCode.length() >= 6) {
                    String proviceCode = areaCode.substring(0, 2);
                    domesticWeather.setProvincecode(proviceCode);
                    domesticWeather.setProvince(areaList.get(proviceCode));
                    String cityCode = areaCode.substring(0, 4);
                    domesticWeather.setCitycode(cityCode);
                    domesticWeather.setCity(areaList.get(cityCode));
                    String countyCode = areaCode.substring(0, 6);
                    domesticWeather.setCountycode(countyCode);
                    domesticWeather.setCounty(areaList.get(countyCode));
                } else if (areaCode.length() >= 4) {
                    String proviceCode = areaCode.substring(0, 2);
                    domesticWeather.setProvincecode(proviceCode);
                    domesticWeather.setProvince(areaList.get(proviceCode));
                    String cityCode = areaCode.substring(0, 4);
                    domesticWeather.setCitycode(cityCode);
                    domesticWeather.setCity(areaList.get(cityCode));
                } else if (areaCode.length() >= 2) {
                    String proviceCode = areaCode.substring(0, 2);
                    domesticWeather.setProvincecode(proviceCode);
                    domesticWeather.setProvince(areaList.get(proviceCode));
                } else {
                    throw new Exception("Invalid area code length: " + areaCode.length());
                }

                List<String> ignoreColumns = new ArrayList<String>();
                ignoreColumns.add("id");
                CompletableFuture<Integer> addFuture = Rep.addAsync(
                        (Class<FS_DomesticWeather>) domesticWeather.getClass(),
                        domesticWeather,
                        ignoreColumns);
                affectedRow = addFuture.join();
            }
        } catch (Exception ex) {
            CommonUtil.printThreadLog("出现异常：" + ex.getMessage());
        }
        return affectedRow > 0;
    }

    private Map<String, String> getAreaList(String areaCode) throws Exception {
        Map<String, String> dicAreaInfos = new HashMap<String, String>();
        List<String> areaCodeList = new ArrayList<String>();
        List<String> searchAreaCodeList = new ArrayList<String>();
        if (areaCode != null) {
            if (areaCode.length() >= 6) {
                areaCodeList.add(areaCode.substring(0, 2)); // 省
                areaCodeList.add(areaCode.substring(0, 4)); // 市
                areaCodeList.add(areaCode.substring(0, 6));// 区县
            } else if (areaCode.length() >= 4) {
                areaCodeList.add(areaCode.substring(0, 2)); // 省
                areaCodeList.add(areaCode.substring(0, 4)); // 市
            } else if (areaCode.length() >= 2) {
                areaCodeList.add(areaCode.substring(0, 2)); // 省
            } else {
                throw new Exception("Invalid area code length: " + areaCode.length());
            }

            for (String code : areaCodeList) {
                String areaName = LettuceRedisHelper.hget(SystemVariables.Service_AreaCode_Key, code);
                if (areaName != null) {
                    dicAreaInfos.put(code, areaName);
                } else {
                    searchAreaCodeList.add(code);
                }
            }

            // 去数据库查找数据
            if (searchAreaCodeList.size() > 0) {
                AdministrativeDivisionQuery query = new AdministrativeDivisionQuery();
                query.setCodeList(searchAreaCodeList);
                query.setSearchCount(false);
                Map.Entry<Integer, List<TB_AdministrativeDivision>> entry = AdministrativeDivisionRep
                        .getNewPageList(query).get();
                if (entry != null) {
                    if (entry.getValue() != null) {
                        for (TB_AdministrativeDivision area : entry.getValue()) {
                            if (area.getCode() != null && area.getName() != null) {
                                LettuceRedisHelper.hset(SystemVariables.Service_AreaCode_Key, area.getCode(),
                                        area.getName());
                                dicAreaInfos.put(area.getCode(), area.getName());
                            }
                        }
                    } else {
                        throw new Exception(
                                "No administrative division found for area code: " + String.join(",", areaCodeList));
                    }
                }
            }
        } else {
            throw new Exception("Area code cannot be null or empty");
        }
        return dicAreaInfos;
    }

}
